define('three.effectComposer', ['THREE'], function (THREE) {

    //https://github.com/hughsk/three-effectcomposer

    var CopyShader = {
        uniforms: {
            tDiffuse: {
                type: "t",
                value: null
            },
            opacity: {
                type: "f",
                value: 1
            }
        },
        vertexShader: ["varying vec2 vUv;", "void main() {", "vUv = uv;", "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", "}"].join("\n"),
        fragmentShader: ["uniform float opacity;", "uniform sampler2D tDiffuse;", "varying vec2 vUv;", "void main() {", "vec4 texel = texture2D( tDiffuse, vUv );", "gl_FragColor = opacity * texel;", "}"].join("\n")
    };

    function EffectComposer(renderer, renderTarget) {
        this.renderer = renderer;
        if (renderTarget === undefined) {
            var parameters = {
                minFilter: THREE.LinearFilter,
                magFilter: THREE.LinearFilter,
                format: THREE.RGBAFormat,
                stencilBuffer: false
            };
            var size = renderer.getSize(new THREE.Vector2());
            renderTarget = new THREE.WebGLRenderTarget(size.width, size.height, parameters);
        }

        this.renderTarget1 = renderTarget;
        this.renderTarget2 = renderTarget.clone();

        this.writeBuffer = this.renderTarget1;
        this.readBuffer = this.renderTarget2;

        this.passes = [];

        if (!CopyShader) {
            console.error("THREE.EffectComposer relies on THREE.CopyShader");
        }

        this.copyPass = new ShaderPass(CopyShader);
    }

    EffectComposer.prototype = {
        swapBuffers: function () {
            var tmp = this.readBuffer;
            this.readBuffer = this.writeBuffer;
            this.writeBuffer = tmp;
        },
        addPass: function (pass) {
            this.passes.push(pass);
        },
        insertPass: function (pass, index) {
            this.passes.splice(index, 0, pass);
        },
        render: function (delta) {
            this.writeBuffer = this.renderTarget1;
            this.readBuffer = this.renderTarget2;
            var maskActive = false;

            var pass, i, il = this.passes.length;

            for (i = 0; i < il; i++) {
                pass = this.passes[i];
                if (!pass.enabled) continue;

                pass.render(this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive);

                if (pass.needsSwap) {
                    if (maskActive) {
                        var context = this.renderer.getContext();
                        context.stencilFunc(context.NOTEQUAL, 1, 0xffffffff);
                        this.copyPass.render(this.renderer, this.writeBuffer, this.readBuffer, delta);
                        context.stencilFunc(context.EQUAL, 1, 0xffffffff);
                    }
                    this.swapBuffers();
                }

                if (pass instanceof MaskPass) {
                    maskActive = true;
                } else if (pass instanceof ClearMaskPass) {
                    maskActive = false;
                }
            }
        },
        reset: function (renderTarget) {
            if (renderTarget === undefined) {
                var size = this.renderer.getSize(new THREE.Vector2());
                renderTarget = this.renderTarget1.clone();
                renderTarget.setSize(size.width, size.height)
            }
            this.renderTarget1.dispose();
            this.renderTarget2.dispose();
            this.renderTarget1 = renderTarget;
            this.renderTarget2 = renderTarget.clone();
            this.writeBuffer = this.renderTarget1;
            this.readBuffer = this.renderTarget2;
        },
        setSize: function (width, height) {
            this.renderTarget1.setSize(width, height);
            this.renderTarget2.setSize(width, height);
        }
    };

    function Pass() {
        this.enabled = true;
        this.needsSwap = true;
        this.clear = false;
        this.renderToScreen = false
    }

    Pass.prototype = {
        constructor: Pass,
        render: function (a, b, c, d, e) {
            console.error("THREE.Pass: .render() must be implemented in derived pass.")
        }
    };

    // Not used in SMap
    function MaskPass(scene, camera) {
        Pass.call(this);
        this.scene = scene;
        this.camera = camera;
        this.clear = true;
        this.needsSwap = false;
        this.inverse = false
    }

    MaskPass.prototype = Object.create(Pass.prototype);
    MaskPass.prototype = {
        constructor: MaskPass,
        render: function (renderer, writeBuffer, readBuffer, delta) {
            var context = renderer.getContext();
            context.colorMask(false, false, false, false);
            context.depthMask(false);

            // set up stencil
            var writeValue, clearValue;
            if (this.inverse) {
                writeValue = 0;
                clearValue = 1;
            } else {
                writeValue = 1;
                clearValue = 0;
            }

            context.enable(context.STENCIL_TEST);
            context.stencilOp(context.REPLACE, context.REPLACE, context.REPLACE);
            context.stencilFunc(context.ALWAYS, writeValue, 0xffffffff);
            context.clearStencil(clearValue);

            // draw into the stencil buffer
            renderer.render(this.scene, this.camera, readBuffer, this.clear);
            renderer.render(this.scene, this.camera, writeBuffer, this.clear);

            // re-enable update of color and depth
            context.colorMask(true, true, true, true);
            context.depthMask(true);

            // only render where stencil is set to 1
            context.stencilFunc(context.EQUAL, 1, 0xffffffff);  // draw if == 1
            context.stencilOp(context.KEEP, context.KEEP, context.KEEP);
        }
    };

    // Not used in SMap
    function ClearMaskPass() {
        Pass.call(this);
        this.needsSwap = false
    }

    ClearMaskPass.prototype = Object.create(Pass.prototype);
    ClearMaskPass.prototype = {
        constructor: ClearMaskPass,
        render: function (renderer, writeBuffer, readBuffer, delta) {
            var context = renderer.getContext();
            context.disable(context.STENCIL_TEST);
        }
    };

    function RenderPass(scene, camera, overrideMaterial, clearColor, clearAlpha) {
        Pass.call(this);
        this.scene = scene;
        this.camera = camera;
        this.overrideMaterial = overrideMaterial;
        this.clearColor = clearColor;
        this.clearAlpha = void 0 !== clearAlpha ? clearAlpha : 1;
        this.oldClearColor = new THREE.Color;
        this.oldClearAlpha = 1;
        this.clear = true;
        this.needsSwap = false
    }

    RenderPass.prototype = Object.create(Pass.prototype);
    RenderPass.prototype = {
        constructor: RenderPass,
        render: function (renderer, writeBuffer, readBuffer, delta) {
            this.scene.overrideMaterial = this.overrideMaterial;
            if (this.clearColor) {
                this.oldClearColor.copy(renderer.getClearColor());
                this.oldClearAlpha = renderer.getClearAlpha();
                renderer.setClearColor(this.clearColor, this.clearAlpha);
            }
            renderer.render(this.scene, this.camera, readBuffer, this.clear);
            if (this.clearColor) {
                renderer.setClearColor(this.oldClearColor, this.oldClearAlpha);
            }
            this.scene.overrideMaterial = null;
        }
    };

    function ShaderPass(shader, textureID) {
        Pass.call(this);
        this.textureID = void 0 !== textureID ? textureID : "tDiffuse";
        if (shader instanceof THREE.ShaderMaterial) {
            this.uniforms = shader.uniforms;
            this.material = shader;
        } else {
            this.uniforms = THREE.UniformsUtils.clone(shader.uniforms);
            this.material = new THREE.ShaderMaterial({
                defines: shader.defines || {},
                uniforms: this.uniforms,
                vertexShader: shader.vertexShader,
                fragmentShader: shader.fragmentShader
            });
        }
        this.camera = new THREE.OrthographicCamera((-1), 1, 1, (-1), 0, 1);
        this.scene = new THREE.Scene;
        this.quad = new THREE.Mesh(new THREE.PlaneBufferGeometry(2, 2), null);
        this.scene.add(this.quad)
    }

    ShaderPass.prototype = Object.create(Pass.prototype);
    ShaderPass.prototype = {
        constructor: ShaderPass,
        render: function (renderer, writeBuffer, readBuffer, delta) {
            if (this.uniforms[this.textureID]) {
                this.uniforms[this.textureID].value = readBuffer.texture || readBuffer;
            }
            this.quad.material = this.material;
            if (this.renderToScreen) {
                renderer.render(this.scene, this.camera);
            } else {
                renderer.render(this.scene, this.camera, writeBuffer, this.clear);
            }

        }
    };

    THREE.CopyShader = CopyShader;
    THREE.EffectComposer = EffectComposer;
    THREE.Pass = Pass;
    THREE.MaskPass = MaskPass;
    THREE.ClearMaskPass = ClearMaskPass;
    THREE.RenderPass = RenderPass;
    THREE.ShaderPass = ShaderPass;

    return THREE;
});